import * as Mysql from 'mysql';

// 数据库连接
export class DbConn{
    protected conn: Mysql.PoolConnection;

    Init(conn: Mysql.PoolConnection): DbConn{
        this.conn = conn;
        return this;
    }

    Release(){
        if (this.conn != null){
            this.conn.release();
        }
    }

    // 返回Insert的新的ID
    async Insert(sql: string, data: object): Promise<number>{
        let conn = this.conn;
        let promise = function(resolve: Function, reject: Function){
            try{
                let callback = function (err: any, res: any, fields: any) {
                    if (err) return reject(err);

                    let id = res.insertId;
                    resolve(id);
                };

                // 执行数据库查询
                conn.query(sql, data, callback);
            }catch(err){
                reject(err);
            }
        }

        return new Promise<number>(promise.bind(this));
    }

    // 返回收到影响的行数
    async Excute(sql: string): Promise<number>{
        let conn = this.conn;

        let promise = function(resolve: Function, reject: Function){
            try{
                let callback = function (err: any, res: any, fields: any) {
                    if (err) return reject(err);

                    let rows = res.affectedRows;
                    resolve(rows);
                };

                // 执行数据库查询
                conn.query(sql, callback);
            }catch(err){
                reject(err);
            }
        }

        return new Promise<number>(promise.bind(this));
    }

    // 执行查询语句，返回数据结果
    async Query<T>(sql: string, para: any):Promise<T>{
        let conn = this.conn;

        let fun = (resolve: Function, reject: Function) => {
            try{
                let callback = function (error: any, results: any, fields: any) {
                    if (error) return reject(error);

                    let data = <T>results;
                    resolve(data);
                };

                // 执行数据库查询
                conn.query(sql, para, callback);
            }catch(err){
                reject(err);
            }
        };
        return new Promise<T>(fun.bind(this));
    }

    async BeginTransaction(){
        let sql = "START TRANSACTION";
        return await this.Excute(sql);
    }

    async Commit(){
        let sql = "COMMIT";
        return await this.Excute(sql);
    }

    async Rollback(){
        let sql = "ROLLBACK";
        return await this.Excute(sql);
    }
}

// 数据库连接池
export class DbConnPool {
    private pool: Mysql.Pool;

    // 初始化数据库连接池
    Init(optProd: Mysql.PoolConfig, optDev: Mysql.PoolConfig): DbConnPool{
        if (process.env.NODE_ENV == "production"){
            this.pool = Mysql.createPool(optProd);
        }else{
            this.pool = Mysql.createPool(optDev);
        }
        
        return this;
    }

    // 获取一个数据库连接
    async FactoryBuildConn(): Promise<DbConn>{
        let conn = await this.GetConn();
        let dbConn = new DbConn().Init(conn);

        return dbConn;
    }

    async GetConn(): Promise<Mysql.PoolConnection>{
        let pool = this.pool;
        let fun = (resolve: Function, reject: Function) => {
            let callback = function (err: Mysql.MysqlError, conn: Mysql.PoolConnection){
                if (err == null){
                    resolve(conn); // await的返回
                }else{
                    reject(err);
                }
            };
            pool.getConnection(callback);
        };

        return new Promise<Mysql.PoolConnection>(fun);
    }

    // 返回Insert的新的ID
    async Insert(sql: string, data: object): Promise<number>{
        let conn = await this.GetConn();

        let promise = function(resolve: Function, reject: Function){
            try{
                let callback = function (err: any, res: any, fields: any) {
                    conn.release();

                    if (err) return reject(err);

                    let id = res.insertId;
                    resolve(id);
                };

                // 执行数据库查询
                conn.query(sql, data, callback);
            }catch(err){
                reject(err);
            }
        }

        return new Promise<number>(promise.bind(this));
    }

    // 返回收到影响的行数
    async Excute(sql: string): Promise<number>{
        let conn = await this.GetConn();

        let promise = function(resolve: Function, reject: Function){
            try{
                let callback = function (err: any, res: any, fields: any) {
                    conn.release();

                    if (err) {
                        reject(err);
                        return;
                    }

                    let rows = res.affectedRows;
                    resolve(rows);
                };

                // 执行数据库查询
                conn.query(sql, callback);
            }catch(err){
                reject(err);
            }
        }

        return new Promise<number>(promise.bind(this));
    }

    async Query<T>(sql: string, para: any):Promise<T>{
        let conn = await this.GetConn();

        let fun = (resolve: Function, reject: Function) => {
            try{
                let callback = function (error: any, results: any, fields: any) {
                    conn.release();

                    if (error) reject(error);

                    let data = <T>results;
                    resolve(data);
                };

                // 执行数据库查询
                conn.query(sql, para, callback);
            }catch(err){
                reject(err);
            }
        };
        return new Promise<T>(fun.bind(this));
    }
}

let dbWzlzOpt = {
    connectionLimit : 1000,
    host            : '10.9.82.36',
    port: 3306,
    user            : 'root',
    password        : 'Tentap10086',
    database        : 'wzlz_payment_log',
    charset: "utf8mb4_general_ci"
};

let dbWzlzOptDev = {
    connectionLimit : 5,
    host            : 'localhost',
    port: 8889,
    user            : 'root',
    password        : 'root',
    database        : 'wzlz_payment_log',
    charset: "utf8mb4_general_ci"
};

export var ConnPoolInstance = new DbConnPool().Init(dbWzlzOpt, dbWzlzOptDev);

